﻿using System;
using System.Collections.Generic;

namespace Vectors
{
    public class Vector3D
    {
        protected bool Equals(Vector3D other)
        {
            return Equals(_vector, other._vector);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;
            return Equals((Vector3D) obj);
        }

        public override int GetHashCode()
        {
            return (_vector != null ? _vector.GetHashCode() : 0);
        }

        private readonly double[] _vector;

        public double X
        {
            set { _vector[0] = value; }
            get { return _vector[0]; }
        }

        public double Y
        {
            set { _vector[1] = value; }
            get { return _vector[1]; }
        }
        public double Z
        {
            set { _vector[2] = value; }
            get { return _vector[2]; }
        }

        public Vector3D(double x, double y, double z)
        {
            _vector = new double[3];
            _vector[0] = x;
            _vector[1] = y;
            _vector[2] = z;
        }

        public Vector3D(IList<double> vec)
        {
            int n = vec.Count;
            if (n != 3) throw new Exception("Inncorect dimention.");
            _vector = new double[n];
            for (int i = 0; i < n; i++)
                _vector[i] = vec[i];
        }

        public static double ScalarProduct(Vector3D vector1,Vector3D vector2)
        {
            var sc = 0d;
            for (var i = 0; i < 3; i++)
            {
                sc += vector1[i]*vector2[i];
            }
            return sc;
        }

        public double Norm()
        {
            var sc = ScalarProduct(this,this);
            return Math.Sqrt(sc);
        }

       /* public void Normalize()
        {
            var norm = Norm();
            for (var i = 0; i < _vector.Length; i++)
                _vector[i] = _vector[i] / norm;
        }*/

        public void Normalize()
        {
            var norm = Norm();
            for (var i = 0; i < _vector.Length; i++)
                _vector[i] = _vector[i] / norm;
        }


        public static Vector3D CrossProduct(Vector3D vector1,Vector3D vector2)
        {
            var res = new Vector3D(0, 0, 0)
                {
                    X = vector1.Y * vector2.Z - vector1.Z * vector2.Y,
                    Y = vector1.Z * vector2.X - vector1.X * vector2.Z,
                    Z = vector1.X * vector2.Y - vector1.Y * vector2.X
                };
            return res;
        }

        public double this[int index]
        {
            get
            {
                if (index<0 || index>=3) throw new IndexOutOfRangeException();
                return _vector[index];
            }

            set
            {
                if (index < 0 || index >= 3) throw new IndexOutOfRangeException();
                _vector[index] = value;
            }
        }
        
        
        public static Boolean operator ==(Vector3D vector1, Vector3D vector2)
        {
            var areEqual = true;

            if (ReferenceEquals(null, vector1) || ReferenceEquals(null, vector2))
                throw new NullReferenceException();

            for (var i = 0; i < 3; i++)
            {
                if (Math.Abs(vector1[i] - vector2[i]) > 0.001) areEqual = false;
            }

            return areEqual;
        }

        public static Boolean operator !=(Vector3D vector1, Vector3D vector2)
        {
            return !(vector1 == vector2);
        }

        public static Vector3D operator +(Vector3D vector1, Vector3D vector2)
        {
            var vectorRes = new Vector3D(0, 0, 0);
            for (int i = 0; i < 3; i++)
            {
                vectorRes[i] = vector1[i] + vector2[i];
            }
            return vectorRes;
        }

        public static Vector3D operator -(Vector3D vector)
        {
            var vectorRes = new Vector3D(0, 0, 0);
            for (int i = 0; i < 3; i++)
            {
                vectorRes[i] = -vector[i];
            }
            return vectorRes;
        }

        public static Vector3D operator-(Vector3D vector1, Vector3D vector2)
        {
            vector2 = -vector2;
            var vectorRes = vector1 + vector2;
            return vectorRes;
        }

        public Vector3D Copy()
        {
            var vectorRes=new Vector3D(_vector[0],_vector[1],_vector[2]);
            return vectorRes;
        }

    }
}
